/*
 *  Copyright (C) 2010 Matthias Buch-Kromann <mbk.isv@cbs.dk>
 * 
 *  This file is part of the IncrementalParser package.
 *  
 *  The IncrementalParser program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.osdtsystem.incparser.graphs;

import org.osdtsystem.incparser.featureextraction.FeatureExtractor;
import org.osdtsystem.incparser.features.FeatureAggregatorFeatureVector;
import org.osdtsystem.incparser.features.FeatureAggregatorScore;
import org.osdtsystem.incparser.features.FeatureHandler;
import org.osdtsystem.incparser.features.FeatureVector;
import org.osdtsystem.incparser.features.FeatureVectorSparse;
import org.osdtsystem.incparser.features.WeightVector;

/**
 *
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
public abstract class AbstractGraphScorer implements GraphScorer, FeatureExtractorOutdateListener {
    final int scorer;
    final FeatureAggregatorScore scoreAggregator;
    final FeatureAggregatorFeatureVector featureVectorAggregator;
    final FeatureExtractor[] extractors;

    public AbstractGraphScorer(BaseGraph graph, WeightVector weights, FeatureHandler featureHandler,
            FeatureExtractor... extractors) {
        this.scorer = graph.addGraphScorer(this);
        this.scoreAggregator = new FeatureAggregatorScore(weights, featureHandler, scorer);
        this.featureVectorAggregator = new FeatureAggregatorFeatureVector(weights, featureHandler, scorer);
        this.extractors = extractors;
        for (FeatureExtractor extractor : extractors) {
            graph.addGraphListener(extractor, extractor.layers());
            extractor.addOutdateListener(this);
        }
    }

    public final void featureVectorAddTo(Graph graph, int node, FeatureVector featureVector) {
        featureVector(graph, node).addTo(1, featureVector);
    }

    public final void featureVectorAddTo(Graph graph, FeatureVector featureVector) {
        for (int i = 0; i < extractors.length; ++i) {
            FeatureExtractor extractor = extractors[i];
            for (int node = 0; node < graph.nodes(); ++node) {
                featureVector(graph, node, extractor).addTo(1, featureVector);
            }
        }
    }

    FeatureVector featureVector(Graph graph, int node, FeatureExtractor extractor) {
        FeatureVector featureVector = new FeatureVectorSparse();
        featureVectorAggregator.clear();
        featureVectorAggregator.pushFeatureVector(featureVector);
        extractor.extract(featureVectorAggregator, graph, node);
        featureVectorAggregator.popFeatureVector();
        featureVector.toSet();
        return featureVector;
    }

    public FeatureVector featureVector(Graph graph, int node) {
        FeatureVector featureVector = new FeatureVectorSparse();
        for (int i = 0; i < extractors.length; ++i) {
            featureVector(graph, node, extractors[i]).addTo(1, featureVector);
        }
        return featureVector;
    }

    public FeatureVector featureVector(Graph graph) {
        FeatureVector featureVector = new FeatureVectorSparse();
        featureVectorAddTo(graph, featureVector);
        return featureVector;
    }

    public float score(Graph graph) {
        double score = 0;
        for (int node = 0; node < graph.nodes(); ++node)
            score += score(graph, node);
        return (float) score;
    }

    public float score(Graph graph, int node) {
        scoreAggregator.clear();
        for (int i = 0; i < extractors.length; ++i)
            extractors[i].extract(scoreAggregator, graph, node);
        return (float) scoreAggregator.score();
    }

    public FeatureExtractor[] extractors() {
        return extractors;
    }

    public void outdate(Graph graph, int node) {
        graph.outdateScore(node, scorer);
    }
}
